---
layout: layout.njk
permalink: "{{ page.filePathStem }}.html"
title: Smile - Wavelet
---
{% include "toc.njk" %}

<div class="col-md-9 col-md-pull-3">

    <h1 id="wavelet-top" class="title">Wavelet</h1>

    <p>A wavelet is a wave-like oscillation with an amplitude that begins
        at zero, increases, and then decreases back to zero. Generally,
        wavelets are intentionally crafted to have specific properties
        that make them useful for signal processing. Wavelets can be combined,
        with portions of a known signal by convolution to extract
        information from the unknown signal.</p>

    <p>In continuous wavelet transforms, a given signal of finite energy
        is projected on a continuous family of frequency bands (or similar
        subspaces of the <code>L<sup>p</sup></code> function space
        <code>L<sup>2</sup>(R)</code>). For instance the signal may be
        represented on every frequency band of the form <code>[f, 2f]</code>
        for all positive frequencies <code>f > 0</code>. Then, the original
        signal can be reconstructed by a suitable integration over all
        the resulting frequency components.</p>

    <p>It is computationally impossible to analyze a signal using all
        wavelet coefficients. Instead, one may pick a discrete subset of
        the upper halfplane to be able to reconstruct a signal from the
        corresponding wavelet coefficients. That is, a discrete wavelet transform
        (DWT) is any wavelet transform for which the wavelets are
        discretely sampled.</p>

    <p>Like the fast Fourier transform (FFT), the discrete wavelet transform
        is a fast, linear operation that operates on a data vector whose
        length is an integer power of 2, transforming it into a numerically
        different vector of the same length. The wavelet transform is
        invertible and in fact orthogonal. Both FFT and DWT can be viewed as
        a rotation in function space. A key advantage it has over Fourier
        transforms is temporal resolution: it captures both frequency
        and location information (location in time).</p>

    <h2 id="filter" class="title">Wavelet Filters</h2>

    <p>In Java, Smile provides classes for well known wavelets such as
        Haar, Daubechies, Least Asymetric, Best Localized and Coiflet.
        One may also define new filters by provide coefficients.
        In Scala/Kotlin, The below function returns a wavelet filter.
        The filter name is derived from one of four classes of wavelet
        transform filters: Daubechies, Least Asymetric, Best Localized and Coiflet.
        The prefixes for filters of these classes are <code>d</code>, <code>la</code>,
        <code>bl</code> and <code>c</code>, respectively. Following the
        prefix, the filter name consists of an integer indicating length.
        Supported lengths are as follows:</p>
    <dl>
        <dt>Daubechies</dt>
        <dd>4,6,8,10,12,14,16,18,20.</dd>
        <dt>Least Asymetric</dt>
        <dd>8,10,12,14,16,18,20.</dd>
        <dt>Best Localized</dt>
        <dd>14,18,20.</dd>
        <dt>Coiflet</dt>
        <dd>6,12,18,24,30.</dd>
    </dl>
    <p>Additionally, "haar" is supported for Haar wavelet. Besides, "d4", the
        simplest and most localized wavelet, uses a different centering method
        from other Daubechies wavelet.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#java_1" data-toggle="tab">Java</a></li>
        <li><a href="#scala_1" data-toggle="tab">Scala</a></li>
        <li><a href="#kotlin_1" data-toggle="tab">Kotlin</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="java_1">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-java"><code>
    public Wavelet(double[] coefficients)
    </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="scala_1">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-scala"><code>
    def wavelet(filter: String): Wavelet
    </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="kotlin_1">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-kotlin"><code>
    fun wavelet(filter: String): Wavelet
    </code></pre>
            </div>
        </div>
    </div>

    <h2 id="dwt" class="title">Discrete Wavelet Transform</h2>

    <p>With a wavelet object, we can compute the discrete wavelet transform
        coefficients for a univariate time series. The size of time series
        array should be a power of 2. For time series of size no power of 2,
        0 padding can be applied.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#java_2" data-toggle="tab">Java</a></li>
        <li><a href="#scala_2" data-toggle="tab">Scala</a></li>
        <li><a href="#kotlin_2" data-toggle="tab">Kotlin</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane" id="scala_2">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-scala"><code>
    val sp500 = Array(
        1103.96, 1107.84, 1114.11, 1108.61, 1106.36, 1097.86, 1105.31,
        1114.51, 1118.84, 1121.08, 1127.53, 1128.55, 1125.53, 1126.60,
        1116.56, 1132.66, 1135.71, 1136.27, 1140.52, 1145.96, 1143.81,
        1137.31, 1145.68, 1147.72, 1136.03, 1147.95, 1138.68, 1115.49,
        1092.40, 1095.80, 1091.94, 1096.93, 1087.61, 1073.89, 1090.05,
        1100.67, 1097.25, 1064.12, 1065.51, 1060.06, 1069.68, 1067.10,
        1075.95, 1079.13, 1096.14, 1099.03, 1105.49, 1110.00, 1107.49,
        1095.89, 1101.24, 1103.10, 1105.36, 1117.01, 1119.36, 1119.12,
        1125.12, 1138.40, 1137.56, 1140.22, 1143.96, 1151.71, 1148.53,
        1150.83, 1159.94, 1166.13, 1166.68, 1157.25, 1166.47, 1172.70,
        1170.03, 1167.58, 1167.71, 1173.75, 1171.75, 1171.23, 1178.71,
        1186.01, 1188.23, 1181.75, 1187.47, 1194.94, 1195.94, 1198.69,
        1210.77, 1210.17, 1192.06, 1199.04, 1207.16, 1202.52, 1207.87,
        1217.07, 1209.92, 1184.59, 1193.30, 1206.77, 1188.58, 1197.50,
        1169.24, 1164.38, 1127.04, 1122.27, 1156.39, 1155.43, 1170.04,
        1157.19, 1136.52, 1138.78, 1119.57, 1107.34, 1067.26, 1084.78,
        1067.42, 1075.51, 1074.27, 1102.59, 1087.30, 1073.01, 1098.82,
        1098.43, 1065.84, 1050.81, 1062.75, 1058.77, 1082.65, 1095.00,
        1091.21, 1114.02, 1115.98, 1116.16, 1122.79, 1113.90, 1095.57,
        1090.93, 1075.10, 1077.50, 1071.10, 1040.56, 1031.10, 1027.65,
        1028.09, 1028.54, 1062.92, 1070.50, 1077.23, 1080.65, 1095.61,
        1094.46, 1093.85, 1066.85, 1064.53, 1086.67, 1072.14, 1092.17,
        1102.89, 1117.36, 1112.84, 1108.07, 1098.44, 1107.53, 1125.34,
        1121.06, 1125.78, 1122.07, 1122.80, 1122.92, 1116.89, 1081.48,
        1082.22, 1077.49, 1081.16, 1092.08, 1092.44, 1075.63, 1073.36,
        1063.20, 1048.98, 1056.28, 1049.27, 1062.90, 1046.88, 1049.72,
        1080.66, 1093.61, 1102.60, 1092.36, 1101.15, 1104.57, 1113.38,
        1121.16, 1119.43, 1123.89, 1126.39, 1126.57, 1142.82, 1139.49,
        1131.10, 1131.69, 1148.64, 1142.31, 1146.75, 1145.97, 1143.49,
        1144.96, 1140.68, 1159.81, 1161.57, 1158.36, 1165.32, 1164.28,
        1171.32, 1177.82, 1177.47, 1176.83, 1178.64, 1166.74, 1179.82,
        1180.52, 1184.74, 1184.88, 1183.84, 1184.47, 1183.87, 1185.71,
        1187.86, 1193.79, 1198.34, 1221.20, 1223.24, 1223.59, 1213.14,
        1213.04, 1209.07, 1200.44, 1194.79, 1178.33, 1183.75, 1196.12,
        1198.07, 1192.51, 1183.70, 1194.16, 1189.08, 1182.96, 1186.60,
        1206.81, 1219.93, 1223.87, 1227.25, 1225.02, 1230.14, 1233.85,
        1242.52, 1241.84, 1241.58, 1236.34
    )

    val haar = wavelet("haar")
    haar.transform(sp500)
    </code></pre>
            </div>
        </div>
        <div class="tab-pane active" id="java_2">
            <div class="code" style="text-align: left;">
          <pre class="prettyprint lang-java"><code>
    double[] sp500 = {
        1103.96, 1107.84, 1114.11, 1108.61, 1106.36, 1097.86, 1105.31,
        1114.51, 1118.84, 1121.08, 1127.53, 1128.55, 1125.53, 1126.60,
        1116.56, 1132.66, 1135.71, 1136.27, 1140.52, 1145.96, 1143.81,
        1137.31, 1145.68, 1147.72, 1136.03, 1147.95, 1138.68, 1115.49,
        1092.40, 1095.80, 1091.94, 1096.93, 1087.61, 1073.89, 1090.05,
        1100.67, 1097.25, 1064.12, 1065.51, 1060.06, 1069.68, 1067.10,
        1075.95, 1079.13, 1096.14, 1099.03, 1105.49, 1110.00, 1107.49,
        1095.89, 1101.24, 1103.10, 1105.36, 1117.01, 1119.36, 1119.12,
        1125.12, 1138.40, 1137.56, 1140.22, 1143.96, 1151.71, 1148.53,
        1150.83, 1159.94, 1166.13, 1166.68, 1157.25, 1166.47, 1172.70,
        1170.03, 1167.58, 1167.71, 1173.75, 1171.75, 1171.23, 1178.71,
        1186.01, 1188.23, 1181.75, 1187.47, 1194.94, 1195.94, 1198.69,
        1210.77, 1210.17, 1192.06, 1199.04, 1207.16, 1202.52, 1207.87,
        1217.07, 1209.92, 1184.59, 1193.30, 1206.77, 1188.58, 1197.50,
        1169.24, 1164.38, 1127.04, 1122.27, 1156.39, 1155.43, 1170.04,
        1157.19, 1136.52, 1138.78, 1119.57, 1107.34, 1067.26, 1084.78,
        1067.42, 1075.51, 1074.27, 1102.59, 1087.30, 1073.01, 1098.82,
        1098.43, 1065.84, 1050.81, 1062.75, 1058.77, 1082.65, 1095.00,
        1091.21, 1114.02, 1115.98, 1116.16, 1122.79, 1113.90, 1095.57,
        1090.93, 1075.10, 1077.50, 1071.10, 1040.56, 1031.10, 1027.65,
        1028.09, 1028.54, 1062.92, 1070.50, 1077.23, 1080.65, 1095.61,
        1094.46, 1093.85, 1066.85, 1064.53, 1086.67, 1072.14, 1092.17,
        1102.89, 1117.36, 1112.84, 1108.07, 1098.44, 1107.53, 1125.34,
        1121.06, 1125.78, 1122.07, 1122.80, 1122.92, 1116.89, 1081.48,
        1082.22, 1077.49, 1081.16, 1092.08, 1092.44, 1075.63, 1073.36,
        1063.20, 1048.98, 1056.28, 1049.27, 1062.90, 1046.88, 1049.72,
        1080.66, 1093.61, 1102.60, 1092.36, 1101.15, 1104.57, 1113.38,
        1121.16, 1119.43, 1123.89, 1126.39, 1126.57, 1142.82, 1139.49,
        1131.10, 1131.69, 1148.64, 1142.31, 1146.75, 1145.97, 1143.49,
        1144.96, 1140.68, 1159.81, 1161.57, 1158.36, 1165.32, 1164.28,
        1171.32, 1177.82, 1177.47, 1176.83, 1178.64, 1166.74, 1179.82,
        1180.52, 1184.74, 1184.88, 1183.84, 1184.47, 1183.87, 1185.71,
        1187.86, 1193.79, 1198.34, 1221.20, 1223.24, 1223.59, 1213.14,
        1213.04, 1209.07, 1200.44, 1194.79, 1178.33, 1183.75, 1196.12,
        1198.07, 1192.51, 1183.70, 1194.16, 1189.08, 1182.96, 1186.60,
        1206.81, 1219.93, 1223.87, 1227.25, 1225.02, 1230.14, 1233.85,
        1242.52, 1241.84, 1241.58, 1236.34
    };

    var haar = new HaarWavelet();
    haar.transform(sp500);
          </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="kotlin_2">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-kotlin"><code>
    import smile.wavelet.*;
    val sp500 = doubleArrayOf(
        1103.96, 1107.84, 1114.11, 1108.61, 1106.36, 1097.86, 1105.31,
        1114.51, 1118.84, 1121.08, 1127.53, 1128.55, 1125.53, 1126.60,
        1116.56, 1132.66, 1135.71, 1136.27, 1140.52, 1145.96, 1143.81,
        1137.31, 1145.68, 1147.72, 1136.03, 1147.95, 1138.68, 1115.49,
        1092.40, 1095.80, 1091.94, 1096.93, 1087.61, 1073.89, 1090.05,
        1100.67, 1097.25, 1064.12, 1065.51, 1060.06, 1069.68, 1067.10,
        1075.95, 1079.13, 1096.14, 1099.03, 1105.49, 1110.00, 1107.49,
        1095.89, 1101.24, 1103.10, 1105.36, 1117.01, 1119.36, 1119.12,
        1125.12, 1138.40, 1137.56, 1140.22, 1143.96, 1151.71, 1148.53,
        1150.83, 1159.94, 1166.13, 1166.68, 1157.25, 1166.47, 1172.70,
        1170.03, 1167.58, 1167.71, 1173.75, 1171.75, 1171.23, 1178.71,
        1186.01, 1188.23, 1181.75, 1187.47, 1194.94, 1195.94, 1198.69,
        1210.77, 1210.17, 1192.06, 1199.04, 1207.16, 1202.52, 1207.87,
        1217.07, 1209.92, 1184.59, 1193.30, 1206.77, 1188.58, 1197.50,
        1169.24, 1164.38, 1127.04, 1122.27, 1156.39, 1155.43, 1170.04,
        1157.19, 1136.52, 1138.78, 1119.57, 1107.34, 1067.26, 1084.78,
        1067.42, 1075.51, 1074.27, 1102.59, 1087.30, 1073.01, 1098.82,
        1098.43, 1065.84, 1050.81, 1062.75, 1058.77, 1082.65, 1095.00,
        1091.21, 1114.02, 1115.98, 1116.16, 1122.79, 1113.90, 1095.57,
        1090.93, 1075.10, 1077.50, 1071.10, 1040.56, 1031.10, 1027.65,
        1028.09, 1028.54, 1062.92, 1070.50, 1077.23, 1080.65, 1095.61,
        1094.46, 1093.85, 1066.85, 1064.53, 1086.67, 1072.14, 1092.17,
        1102.89, 1117.36, 1112.84, 1108.07, 1098.44, 1107.53, 1125.34,
        1121.06, 1125.78, 1122.07, 1122.80, 1122.92, 1116.89, 1081.48,
        1082.22, 1077.49, 1081.16, 1092.08, 1092.44, 1075.63, 1073.36,
        1063.20, 1048.98, 1056.28, 1049.27, 1062.90, 1046.88, 1049.72,
        1080.66, 1093.61, 1102.60, 1092.36, 1101.15, 1104.57, 1113.38,
        1121.16, 1119.43, 1123.89, 1126.39, 1126.57, 1142.82, 1139.49,
        1131.10, 1131.69, 1148.64, 1142.31, 1146.75, 1145.97, 1143.49,
        1144.96, 1140.68, 1159.81, 1161.57, 1158.36, 1165.32, 1164.28,
        1171.32, 1177.82, 1177.47, 1176.83, 1178.64, 1166.74, 1179.82,
        1180.52, 1184.74, 1184.88, 1183.84, 1184.47, 1183.87, 1185.71,
        1187.86, 1193.79, 1198.34, 1221.20, 1223.24, 1223.59, 1213.14,
        1213.04, 1209.07, 1200.44, 1194.79, 1178.33, 1183.75, 1196.12,
        1198.07, 1192.51, 1183.70, 1194.16, 1189.08, 1182.96, 1186.60,
        1206.81, 1219.93, 1223.87, 1227.25, 1225.02, 1230.14, 1233.85,
        1242.52, 1241.84, 1241.58, 1236.34
    )

    val haar = wavelet("haar")
    haar.transform(sp500)
    </code></pre>
            </div>
        </div>
    </div>

    <p>The above example transform a S&amp;P 500 time series with Haar
        wavelet. The result is stored in the input array. To transform
        it back, the method <code>inverse</code> can be applied.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#java_3" data-toggle="tab">Java</a></li>
        <li><a href="#scala_3" data-toggle="tab">Scala</a></li>
        <li><a href="#kotlin_3" data-toggle="tab">Kotlin</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane" id="scala_3">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-scala"><code>
    smile&gt; haar.inverse(sp500)
    </code></pre>
            </div>
        </div>
        <div class="tab-pane active" id="java_3">
            <div class="code" style="text-align: left;">
          <pre class="prettyprint lang-java"><code>
    smile&gt; haar.inverse(sp500)
          </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="kotlin_3">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-kotlin"><code>
    >>> haar.inverse(sp500)
    </code></pre>
            </div>
        </div>
    </div>

    <p>In case that you don't want to create the wavelet object
        explicitly or prefer functional APIs, the methods <code>dwt</code> and <code>idwt</code>
        can be used in Scala and Kotlin.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#scala_4" data-toggle="tab">Scala</a></li>
        <li><a href="#kotlin_4" data-toggle="tab">Kotlin</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="scala_4">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-scala"><code>
    // Discrete wavelet transform.
    def dwt(t: Array[Double], filter: String): Unit

    // Inverse discrete wavelet transform.
    def idwt(wt: Array[Double], filter: String): Unit
    </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="kotlin_4">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-kotlin"><code>
    // Discrete wavelet transform.
    fun dwt(t: DoubleArray, filter: String): Unit

    // Inverse discrete wavelet transform.
    fun idwt(wt: DoubleArray, filter: String): Unit
    </code></pre>
            </div>
        </div>
    </div>

    <h2 id="shrinkage" class="title">Wavelet Shrinkage</h2>

    <p>The wavelet shrinkage is a signal denoising technique based on the idea of
        thresholding the wavelet coefficients. Wavelet coefficients having small
        absolute value are considered to encode mostly noise and very fine details
        of the signal. In contrast, the important information is encoded by the
        coefficients having large absolute value. Removing the small absolute value
        coefficients and then reconstructing the signal should produce signal with
        lesser amount of noise. The wavelet shrinkage approach can be summarized as
        follows:</p>
        <ul>
            <li>Apply the wavelet transform to the signal.</li>
            <li>Estimate a threshold value.</li>
            <li>The so-called hard thresholding method zeros the coefficients that are
                smaller than the threshold and leaves the other ones unchanged. In contrast,
                the soft thresholding scales the remaining coefficients in order to form a
                continuous distribution of the coefficients centered on zero.</li>
        <li>Reconstruct the signal (apply the inverse wavelet transform).</li>
        </ul>
    <p>The biggest challenge in the wavelet shrinkage approach is finding an
        appropriate threshold value. In this method, we use the universal threshold
        <code>T = &sigma; sqrt(2*log(N))</code>, where <code>N</code> is the length
        of time series and &sigma; is the estimate of standard deviation of the noise by the
        so-called scaled median absolute deviation (MAD) computed from the high-pass
        wavelet coefficients of the first level of the transform.</p>

    <p>The class <code>WaveletShrinkage</code> implements this process.</p>

    <ul class="nav nav-tabs">
        <li class="active"><a href="#java_5" data-toggle="tab">Java</a></li>
        <li><a href="#scala_5" data-toggle="tab">Scala</a></li>
        <li><a href="#kotlin_5" data-toggle="tab">Kotlin</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane" id="scala_5">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-scala"><code>
    val d4 = wavelet("d4")
    val smooth = sp500.clone()
    WaveletShrinkage.denoise(smooth, d4)
    val canvas = plot(sp500)
    canvas.line(smooth, BLUE)
    show(canvas)
    </code></pre>
            </div>
        </div>
        <div class="tab-pane active" id="java_5">
            <div class="code" style="text-align: left;">
          <pre class="prettyprint lang-java"><code>
    var d4 = new D4Wavelet();
    var smooth = sp500.clone();
    WaveletShrinkage.denoise(smooth, d4);
    var canvas = LinePlot.of(sp500).canvas();
    canvas.add(LinePlot.of(smooth, Color.BLUE));
    canvas.window();
          </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="kotlin_5">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-kotlin"><code>
    import java.awt.Color;
    import smile.plot.swing.*;
    val d4 = wavelet("d4");
    val smooth = sp500.clone();
    WaveletShrinkage.denoise(smooth, d4);
    val canvas = LinePlot.of(sp500).canvas();
    canvas.add(LinePlot.of(smooth, Color.BLUE));
    canvas.window();
    </code></pre>
            </div>
        </div>
    </div>

    <div style="width: 100%; display: inline-block; text-align: center;">
        <img src="images/wavelet-denoise.png" class="enlarge" style="width: 480px;" />
    </div>

    <p>Similar to <code>dwt</code> method, <code>wsdenoise</code> is
        a function for wavelet shrinkage if you don't want to
        create the wavelet object explicitly.</p>
    <ul class="nav nav-tabs">
        <li class="active"><a href="#scala_6" data-toggle="tab">Scala</a></li>
        <li><a href="#kotlin_6" data-toggle="tab">Kotlin</a></li>
    </ul>
    <div class="tab-content">
        <div class="tab-pane active" id="scala_6">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-scala"><code>
    // If the parameter soft is true, apply soft thresholding.
    def wsdenoise(t: Array[Double], filter: String, soft: Boolean = false): Unit
    </code></pre>
            </div>
        </div>
        <div class="tab-pane" id="kotlin_6">
            <div class="code" style="text-align: left;">
    <pre class="prettyprint lang-kotlin"><code>
    // If the parameter soft is true, apply soft thresholding.
    fun wsdenoise(t: DoubleArray, filter: String, soft: Boolean = false): Unit
    </code></pre>
            </div>
        </div>
    </div>

    <div id="btnv">
        <span class="btn-arrow-left">&larr; &nbsp;</span>
        <a class="btn-prev-text" href="statistics.html" title="Previous Section: Statistics"><span>Statistics</span></a>
        <a class="btn-next-text" href="interpolation.html" title="Next Section: Interpolation"><span>Interpolation</span></a>
        <span class="btn-arrow-right">&nbsp;&rarr;</span>
    </div>
</div>

<script type="text/javascript">
    $('#toc').toc({exclude: 'h1, h5, h6', context: '', autoId: true, numerate: false});
</script>
